Skip to content

05. 状态、记忆与上下文工程

版本:v1.2

最后更新:2026-07-09

1. 为什么这一章是 Agent 的分水岭

很多 Demo 看起来能跑,但一进入真实任务就崩,核心原因通常不是模型不够强,而是:

  • 没有设计好状态
  • 没有设计好记忆
  • 没有设计好上下文传递

简单说:

  • 模型能推理
  • 但系统必须帮它“记住该记住的东西”

2. 状态是什么

状态是 任务执行过程中持续存在并会变化的信息

例如:

  • 当前任务目标
  • 已完成步骤
  • 当前轮次
  • 已调用哪些工具
  • 检索到哪些文档
  • 当前审批状态
  • 最近一次错误

如果这些信息只靠模型“自己记住”,长任务就会非常不稳定。

2.1 更像生产系统的状态,通常至少分成四层

很多 Demo 只有一个大对象叫 state,里面什么都塞。

但真实系统里,更稳的做法通常是拆层:

状态层典型内容为什么要单独分层
orchestration state当前节点、下一步、分支判断、handoff 去向这是工作流控制面,不该和工具细节混成一团
execution state工具调用结果、重试次数、超时、最后错误这是执行面,决定是否继续、重试还是升级
evidence state检索证据、引用片段、摘要、草稿版本这是模型真正需要消费的内容来源
governance stateapproval、policy hit、risk level、人工接管点这是治理面,决定哪些动作能不能继续

拆开之后有几个直接好处:

  • trace 更容易读
  • checkpoint 更容易恢复
  • 不同层可以分别做持久化和清理
  • 某一层出问题时,不会把整个对象一起污染

3. 记忆是什么

记忆更偏向:

  • 跨轮次
  • 跨任务
  • 跨会话

保留下来的信息。

例如:

  • 用户偏好
  • 历史项目背景
  • 常用领域术语
  • 历史成功处理方式

4. 短期状态与长期记忆的区别

短期状态

服务于当前这一次任务。

特点:

  • 生命周期短
  • 与执行过程强相关

长期记忆

服务于未来任务。

特点:

  • 生命周期长
  • 与用户、组织、业务事实相关

不要把所有东西都塞进长期记忆,否则系统会越来越脏。

4.1 还有一层经常被忽略:可恢复会话状态

很多团队只区分:

  • 当前轮状态
  • 长期记忆

但生产里通常还需要第三层:

  • durable session state

它既不是“一次请求内的临时变量”,也不是“永久记忆”,而是:

  • 为当前任务链路服务
  • 跨多轮、多工具、多审批点保留
  • 在任务结束或过期后可以清理

典型内容包括:

  • 当前计划版本
  • 已通过的审批点
  • 当前 artifact 引用
  • 最近一次成功 checkpoint
  • 等待中的外部回调

如果这层缺失,系统很容易变成两个极端:

  • 要么什么都不存,恢复不了
  • 要么什么都进长期记忆,越存越脏

5. LangGraph 给我们的一个很好的思路

根据 LangGraph Persistence 文档在 2026-07-01 可访问的说明:

  • checkpointers 用于线程级、短期运行状态
  • stores 用于跨线程、长期数据保存

这个区分非常值得借鉴:

  • 当前任务的中间过程,放到运行状态
  • 未来仍然有价值的事实,再考虑放进长期存储

5.1 OpenAI Sessions 给出的另一个重要边界

OpenAI Agents SDK 当前 Sessions 文档也非常值得一起看,因为它强调的是另一种常见需求:

  • 在多轮 agent runs 之间保留工作上下文

这提醒我们至少要分清三层对象:

对象更像什么适合保存什么
run一次具体执行当前工具调用、当前输出、当前中断
session一段持续交互多轮历史、连续任务上下文、当前工作记忆
memory store跨 session 的长期层稳定事实、偏好、可复用知识

如果这三层不分开,最常见的混乱就是:

  • 把本来只属于当前 run 的中间结论写进长期记忆
  • 把本来只需要会话保留的信息误当成永久事实
  • 以为“有了 session”就不需要显式状态和 checkpoint

更稳的理解通常是:

  • session 解决连续交互
  • state 解决可恢复执行
  • memory 解决跨任务沉淀

6. 为什么不能只靠聊天历史

很多人一开始会把“状态管理”理解成:

  • 把所有历史对话拼进去

这通常不够,原因有 4 个:

  1. 历史越来越长
  2. 噪音越来越多
  3. 关键信息不结构化
  4. 无法稳定恢复任务

真正的状态管理,应该是:

  • 有结构
  • 有字段
  • 有边界

7. 上下文工程是什么

上下文工程可以理解为:

  • 决定在当前这一步,到底要给模型看什么

这和“存了多少信息”不是一回事。

上下文工程要解决的核心问题是:

  1. 哪些信息必须给模型
  2. 哪些信息会干扰模型
  3. 哪些信息该由工具随取随用
  4. 哪些信息应该结构化而不是自然语言拼接

8. 上下文来源通常有哪些

  1. 用户当前输入
  2. 系统提示词
  3. 当前任务状态
  4. 历史对话摘要
  5. 检索出的文档片段
  6. 工具返回结果
  7. 本地上下文或运行依赖

根据 OpenAI Agents SDK define agents 文档在 2026-07-01 的可访问说明:

  • 有些本地上下文应与模型上下文分开管理
  • 比如认证用户信息、数据库客户端、日志器、辅助函数

这非常关键,因为:

  • 不是所有运行上下文都应该发给模型

8.1 更像生产系统的上下文装配顺序

很多系统的问题不是“缺上下文”,而是“上下文装配顺序没有被设计过”。

一个更稳的装配顺序通常是:

  1. 固定策略层:system / developer 规则、输出契约、安全边界。
  2. 任务快照层:当前目标、阶段、最近决定、未决问题。
  3. 证据层:最新有效的检索结果、工具结果、引用材料。
  4. 动作层:当前允许使用的工具、schema、审批约束。
  5. 输出层:这一步到底要产出什么。

这个顺序的价值是:

  • 让稳定规则不要被动态证据淹没
  • 让模型先知道“自己在做什么”,再看“手里有什么”
  • 让工具定义和输出约束始终贴着当前动作

8.2 不要把原始状态对象整包塞给模型

状态表设计得再漂亮,也不等于应该直接把整包 JSON 发给模型。

更稳妥的做法通常是:

  • 应用内部保存全量状态
  • 模型只拿当前决策需要的最小切片
  • 高噪音字段先摘要化或转成人可读结构

否则常见后果是:

  • 模型被内部字段名和无关标记干扰
  • token 花在“系统自己看得懂、模型却不一定看得懂”的内容上
  • 同一个状态对象一膨胀,所有步骤都一起变慢

9. 一个实用的上下文分层思路

可以把上下文分成三层:

第一层:必须发给模型的内容

例如:

  • 当前任务目标
  • 当前可用证据
  • 输出要求

第二层:应用内部要知道,但不必发给模型的内容

例如:

  • 用户 ID
  • 权限信息
  • DB 连接
  • 调试标记

第三层:按需检索的内容

例如:

  • 大量文档
  • 历史案例
  • 表结构
  • 长对话归档

这三层分清楚,很多 Agent 稳定性问题会少很多。


10. RAG 在 Agent 里的作用

RAG 不是 Agent,但常常是 Agent 的重要组成部分。

Agent 中的 RAG 主要用来:

  • 找事实
  • 找依据
  • 找可引用内容

一个成熟的 Agent 通常不会把所有知识都塞进 Prompt,而是:

  1. 先判断是否需要检索
  2. 再检索相关内容
  3. 再把结果带入当前步骤

11. 状态设计时最该保存什么

建议优先保存:

  • 目标
  • 当前步骤
  • 已完成步骤
  • 中间结论
  • 证据引用
  • 错误计数
  • 审批结果
  • 输出草稿版本

不建议盲目保存:

  • 每一句自然语言思考
  • 所有原始上下文全文
  • 无区分的整段对话历史

11.1 checkpoint 最好保存“可恢复最小集”

真正能帮你恢复任务的,往往不是完整历史,而是一组最小可恢复字段。

建议 checkpoint 至少能回答:

  • 当前 run / session 是谁
  • 当前节点和下一步是什么
  • 最近一次工具调用做到哪一步
  • 哪个 artifact / draft 是当前生效版本
  • 哪个 approval / policy 状态已通过
  • 当前引用了哪些证据

如果恢复点里没有这些字段,系统经常会出现:

  • 对话能续上,但副作用对不上
  • 工具结果还在,草稿版本却丢了
  • 审批 UI 还在显示待处理,执行层已经继续了

12. 长期记忆应该存什么

适合长期存的通常是:

  • 用户偏好
  • 组织规则
  • 业务术语
  • 已确认事实
  • 历史成功模板

不适合长期存的通常是:

  • 未验证推测
  • 一次性中间过程
  • 低质量工具输出
  • 敏感临时数据

12.1 长期记忆写入最好走一条显式流水线

更成熟的系统通常不会让模型“觉得有用”就直接写入长期记忆。

更稳的写入流水线通常至少包含:

  1. candidate:先把候选记忆提取出来。
  2. validate:判断它是不是事实、偏好、规则,是否经过验证。
  3. dedupe:和已有记忆做去重或合并。
  4. label:打上来源、置信度、敏感级别、owner、更新时间。
  5. publish:只有过门槛的内容才进入可检索记忆。

这条流水线的价值非常实际:

  • 降低幻觉写入长期记忆的概率
  • 让错误记忆更容易回滚
  • 让不同来源的记忆可以做优先级治理

12.2 记忆不只是要“会写”,还要“会失效”

长期记忆最容易被忽略的问题,是失效和删除。

至少要提前设计:

  • 哪些记忆有 TTL
  • 哪些记忆需要定期再验证
  • 哪些记忆跟随 source of truth 一起撤销
  • 用户偏好和组织规则发生冲突时谁优先

否则系统很容易出现:

  • 老偏好永久压着新偏好
  • 已作废规则还在被召回
  • 已被纠正的事实仍在影响后续任务

13. OpenAI 的状态续接能力,适合解决什么问题

根据 OpenAI Conversation state 文档在 2026-07-07 可访问的说明,Responses API 可以通过 previous_response_id 续接前一个响应链,这对多轮任务和 Agent workflow 很有价值,因为它允许你:

  • 不必每一轮都手工回传全部历史
  • 让模型沿着上一轮的状态继续生成
  • 在需要时重新注入新的工具结果或上下文

但这项能力更像“上下文续接机制”,而不是“完整状态管理系统”。原因是:

  1. 它解决的是模型侧连续性,不自动等于业务状态已经持久化。
  2. 一旦历史对象不可用,应用层仍然要知道怎么回放或重建现场。
  3. 外部副作用、审批状态、租约和权限等对象,本来就应该由应用自己持久化。

所以更稳妥的落地方式通常是:

  • 模型对话链负责保持推理连续性
  • 应用状态表负责保存工作流真实状态
  • 长期记忆层负责沉淀跨任务仍有价值的事实

这三层不要混成一层。


14. 上下文续接不等于 instructions 自动继承

OpenAI Conversation state 文档在 2026-07-07 可访问的说明里,还特别强调了一个容易被忽视的点:

  • previous_response_id 不会自动继承 instructions

这意味着如果你的 Agent 很依赖系统规则、输出约束或安全边界,就不能因为“续接了前一轮”而默认这些规则仍然存在。

更稳妥的做法是:

  1. 把稳定规则放进固定可重建的系统层模板。
  2. 每轮都显式补齐不可丢失的治理约束。
  3. 把会变化的状态字段和稳定的策略字段分开管理。

否则非常容易出现这种隐蔽问题:

  • 任务看起来还在同一条链路上
  • 但关键约束已经悄悄丢了

15. 长期记忆写入要有准入门槛

长期记忆最大的风险不是“没有记住”,而是“记住了不该记的东西”。

所以和数据库建表很像,长期记忆也应该有准入策略。建议至少问四个问题:

  1. 这条信息是否跨任务仍有价值。
  2. 它是事实、偏好还是临时推测。
  3. 它是否经过验证。
  4. 它是否会带来安全或合规风险。

可以把长期记忆粗分成三类:

类型例子是否建议长期保存
稳定事实客户行业、系统约束、术语解释建议
偏好信息输出格式偏好、沟通语言、关注维度谨慎建议
一次性痕迹临时故障、未证实猜测、中间推理不建议

LangGraph Memory overview 的思路也很值得借鉴:

  • checkpointer 负责线程级短期状态
  • store 负责跨线程共享与检索的长期数据

把这个边界想清楚,长期记忆污染会少很多。

12.3 长期记忆最好按“事实 / 偏好 / 过程痕迹”分槽

很多系统的长期记忆之所以越来越脏,一个原因是不同类型的信息都混在同一个桶里。

更像生产系统的做法通常会至少分成三槽:

记忆槽典型内容默认策略
fact memory稳定业务事实、术语、组织规则可检索、可版本化、变更要覆盖旧值
preference memory输出格式偏好、语言偏好、关注维度可更新、冲突时以最近验证值为准
trace residue单次任务中间痕迹、失败尝试、未证实猜测默认不进长期记忆,必要时只进审计层

这样做的价值非常直接:

  • 事实不会和偏好混在一起
  • 偏好不会和一次性失败痕迹混在一起
  • 删除和失效策略可以分开设计

如果不分槽,后面最容易出现的就是:

  • 用户一次性要求被当成永久偏好
  • 临时猜测被当成稳定事实
  • 清理时不知道哪些能删、哪些不能删

12.4 长期记忆写入最好经过“提议 - 验证 - 写入 - 失效”流水线

长期记忆写入如果只是:

  • 模型觉得重要,就直接写

那污染几乎是迟早的事。

更稳的写入流水线通常至少包含四步:

  1. propose:先提出候选记忆
  2. validate:检查是否稳定、是否重复、是否合规
  3. commit:写入对应记忆槽
  4. expire / revise:过期、覆盖或撤销旧值

这条流水线的意义是:

  • 把“模型感觉值得记”变成“系统确认值得记”

尤其在企业环境里,至少还值得额外检查:

  • 是否含敏感信息
  • 是否和现有事实冲突
  • 是否需要 owner 或人工确认
  • 是否需要带时间戳与来源

16. 上下文压缩不是“越短越好”,而是保留决策所需最小集

当任务变长之后,真正的问题通常不是“上下文有没有”,而是:

  • 给模型看的内容里,哪些还在起作用

OpenAI 关于 conversation state 的说明、Anthropic 关于 context windows 的说明,以及 prompt caching 的建议,放在一起看会很有启发:

  • 上下文窗口再大,也不等于应该把全部内容都持续塞进去
  • prompt caching 解决的是重复传输成本,不会神奇地替你降低推理复杂度
  • 需要保留的是对当前决策仍有影响的信息,而不是所有历史痕迹

一个更可执行的压缩顺序通常是:

  1. 保留当前任务目标和约束。
  2. 保留最近有效的工具结果与证据。
  3. 摘要化早期回合,只留下关键决定和结论。
  4. 把大块参考资料转成按需检索,而不是常驻上下文。

压缩做得不好,常见后果不是“模型忘了全部内容”,而是:

  • 模型把次要信息当成重点
  • 响应变慢
  • token 成本快速上升

16.1 prompt caching 不是长期记忆,也不是状态治理

Anthropic 当前 Prompt caching 文档和 OpenAI 当前 Conversation state / Compaction 相关思路放在一起看,很容易得到一个很实用的判断:

  • cache 解决的是重复传输和重复计算成本
  • memory 解决的是跨任务保留什么事实
  • state 解决的是当前任务如何继续

这三件事非常容易被混掉。

例如:

  • 命中 prompt cache,不代表系统已经拥有长期记忆
  • 能续接上一轮 response,不代表执行状态已经可恢复
  • 把所有材料常驻上下文,不代表上下文治理做得好

所以更成熟的上下文设计通常会分开回答:

  1. 哪些前缀值得缓存
  2. 哪些事实值得长期记忆
  3. 哪些状态字段必须持久化
  4. 哪些证据应该按需检索

16.2 上下文压缩最好伴随“决策摘要”,而不是只做字数摘要

很多系统做压缩时只会把历史缩短成更短的一段话。

但对 Agent 来说,更有价值的往往不是“更短”,而是“更利于下一步决策”。

更实用的压缩结果通常至少包括:

  • 当前目标
  • 最近已确认的关键事实
  • 尚未解决的问题
  • 已尝试但失败的路径
  • 下一步可行动作

这类摘要可以理解成:

  • decision summary

而不是普通聊天摘要。

因为 loop 真正需要保留的,不只是聊过什么,而是:

  • 为什么会走到当前这一步

17. 本地运行上下文要和模型可见上下文分层

Agent 系统里有一类信息非常重要,但又不应该直接进入模型上下文,例如:

  • 认证 token
  • 数据库连接
  • 原始日志器
  • 内部调试标志
  • 高权限系统句柄

OpenAI Agents SDK 关于 context 的文档在 2026-07-07 可访问的说明里,就明确把这类对象视作本地运行时上下文,而不是默认发给模型的消息内容。

这层分离的价值非常大:

  1. 能降低泄漏机密的概率。
  2. 能让工具执行层拿到运行依赖,但不污染模型推理。
  3. 能让相同 Agent 在不同宿主里复用,而不是把宿主细节硬编码进 Prompt。

如果系统里还没有这层分离,后面越做越大时很容易出现:

  • 安全边界混乱
  • 提示词越来越脏
  • 工具调试越来越难

17.2 运行时上下文最好显式做脱敏与投影

“本地上下文不要直接给模型”这件事,不应该只靠开发者自觉。

更稳的做法通常是显式设计两层动作:

  1. redaction
  2. projection

也就是:

  • 先把敏感字段、内部句柄、认证信息排除掉
  • 再把模型真正需要的事实投影成可读、可控的上下文片段

例如:

  • 模型不需要知道完整 token
  • 但可能需要知道“当前用户属于哪个角色”
  • 模型不需要知道数据库 client 对象
  • 但可能需要知道“当前查询目标表有哪些字段”

如果没有这一步,你很容易得到一个两头都不好的系统:

  • 要么什么都不给,模型决策缺关键事实
  • 要么全都给,机密和噪音一起泄进去

17.1 副作用动作最好绑定到独立执行记录

很多 Agent 系统的问题,不是模型推理断了,而是:

  • 模型说自己已经做了
  • 实际工具并没有成功执行

所以更稳的做法通常是把高风险动作单独记录成 execution record,例如:

  • tool_call_id
  • approval_id
  • idempotency_key
  • execution_status
  • side_effect_scope
  • resume_token

这样恢复时才能分清:

  • 模型只是计划过
  • 工具已经执行过
  • 工具执行失败但需要补偿
  • 这一步必须人工重新确认

如果没有这层记录,长任务恢复几乎一定会遇到“到底做没做过”的混乱。


18. 常见失败模式

失败模式 1:状态没有字段,只靠自然语言描述

后果:

  • 不可测
  • 不可恢复
  • 很难分支判断

失败模式 2:长期记忆污染

后果:

  • 系统学到错误偏好
  • 后续任务被脏数据影响

失败模式 3:上下文过载

后果:

  • 模型抓不到重点
  • 成本上涨
  • 延迟上涨

失败模式 4:把本地机密上下文直接喂给模型

后果:

  • 安全风险
  • 权限边界混乱

失败模式 5:记忆写入没有准入和失效机制

后果:

  • 错误事实被长期保留
  • 旧偏好一直覆盖新偏好
  • 组织规则更新后,旧规则还在影响输出

失败模式 6:checkpoint 能续对话,续不了执行现场

后果:

  • 模型以为还在同一步
  • 应用层其实已经切到了新状态
  • 工具副作用、审批状态、草稿版本彼此错位

失败模式 7:上下文装配没有固定顺序

后果:

  • 同一任务不同轮次看到的信息结构不断变化
  • 规则、证据、工具约束互相覆盖
  • 回归测试很难定位到底是哪一层变了

19. 重点官方资源

以下资源已按 2026-07-09 复核到当前正式入口;其中部分 OpenAI 页面对脚本访问会返回 403,但浏览器入口仍可正常打开:


20. 这一章最值得落地的实践动作

你可以立刻做下面 6 件事:

  1. 为自己的 Agent 设计一份状态字段表
  2. 区分哪些信息属于长期记忆
  3. 区分哪些运行依赖不该发给模型
  4. 为一个知识库问答系统设计“检索前、检索后、生成前”的上下文结构
  5. 为高风险工具动作补一份 execution record 字段表
  6. 为长期记忆设计写入准入、失效和删除规则

只要这 6 件事做完,你的系统思路就会比大多数只会写 Prompt 的实现稳很多。